package com.allen.app.zdemo.api;

import cn.dev33.satoken.stp.StpUtil;
import com.allen.app.common.BaseController;
import com.allen.app.common.config.aspect.ManyRequest;
import com.allen.app.common.config.other.BusinessException;
import com.allen.app.common.domain.R;
import com.allen.app.common.utils.Jackson;
import com.allen.app.common.utils.Maps;
import com.allen.app.zdemo.domain.DelayExchange;
import com.allen.app.zdemo.domain.DelayExchange.DelayQueues;
import com.allen.app.zdemo.domain.NormalExchange;
import com.allen.app.zdemo.domain.PublishExchange;
import com.allen.app.zdemo.mq.RabbitMqHelper;
import com.allen.app.zdemo.service.TestService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
@Api(tags = "演示demo接口")
public class TestApi extends BaseController {
    private TestService testService;

    @ApiOperation(value = "测试重复点击注解")
    @GetMapping("/test-many-request")
    @ManyRequest(name = "#name")
    public R<?> testManyRequest(String name) {
        return ok(name);
    }

    @ApiOperation(value = "测试分布式锁")
    @GetMapping("/test-lock")
    public R<?> testLock() throws InterruptedException {

        ExecutorService service = Executors.newCachedThreadPool();
        int concurrentNum = 10;
        // 实例化一个倒计数器，N指定计数个数
        CountDownLatch countDownLatch = new CountDownLatch(concurrentNum);
        for (int i = 0; i < concurrentNum; i++) {
            int finalI = i;
            service.execute(()->{
                try {
                    testService.testDistributedLock(finalI);
                } finally {
                    // 计数减一
                    countDownLatch.countDown();
                }
            });
        }
        // 等待，当计数减到0时，所有线程并行执行
        countDownLatch.await();

        return ok();
    }

    @ApiOperation(value = "测试异常-底层钉钉消息发送改成异步发送注解")
    @GetMapping("/test-exception")
    public R<?> testException() {
//        new Thread(()->{
//            try {
//                System.out.println(1/0);
//            } catch (Exception e) {
//                // 线程内异常不能全局异常捕获
//                DingTalkHelper.send(new BusinessException(e));
//            }
//        }).start();
        throw new BusinessException("异常啦");
    }

    @ApiOperation(value = "测试mybatis map返回", notes = "{\n"
        + "    \"key1\": \"第一个字段\",\n"
        + "    \"key1\": \"第二个字段\"\n"
        + "}")
    @GetMapping("/test-mybatis-map")
    public R<List<Map<String, Object>>> testMybatisMap() {
        return ok(
            this.testService.selectMapList()
        );
    }

    @ApiOperation(value = "mq队列测试")
    @GetMapping("/mq-demo")
    public R<?> mqDemo() {

        //mq普通队列
        RabbitMqHelper.convertAndSend(NormalExchange.TEST_MQ_NORMAL.getExchangeName(),
            NormalExchange.TEST_MQ_NORMAL.getQueueName(), Jackson.json(Maps.of("key", "normal")));

        //mq事件通知
        RabbitMqHelper
            .convertAndSend(PublishExchange.TEST_MQ_PUBLISH.getName(), "", Jackson.json(Maps.of("key", "publish")));

        //该延迟队列会存在时间不一致堵塞问题(在同一个队列，必须前一个消费，第二个才能消费。所以时间不一致时会存在堵塞,长时间的堵住短时间的)
        //执行两次 一次60 1次30
        for (int i = 2; i > 0; i--) {
            RabbitMqHelper.convertAndSend(DelayExchange.TEST_MQ_DLX.getExchangeName(),
                DelayQueues.TEST_MQ_DLX_QUEUE.getDelayName(),
                Jackson.json(
                    Maps.of("id", i)
                ),
                i*DelayQueues.TEST_MQ_DLX_QUEUE.getTimeout());

        }

        //执行两次 一次60 1次30
        for (int i = 2; i > 0; i--) {
            RabbitMqHelper.convertAndSendPlugs(DelayExchange.TEST_MQ_PLUGS_DLX.getExchangeName(),
                DelayQueues.TEST_MQ_PLUGS_DLX_QUEUE.getForwardName(),
                Jackson.json(
                    Maps.of("id",i)
                ), i * 5 * DelayQueues.TEST_MQ_PLUGS_DLX_QUEUE.getTimeout(), i);

        }

        return ok();
    }

    // 测试登录，浏览器访问： http://localhost:8081/user/doLogin?username=zhang&password=123456
    @ApiOperation("模拟登录")
    @GetMapping("doLogin")
    public R<?> doLogin(String username, String password) {
        // 此处仅作模拟示例，真实项目需要从数据库中查询数据进行比对
        if("admin".equals(username) && "123456".equals(password)) {
            StpUtil.login(10001);
            // 用户信息可以缓存到session,BaseController 提供一个获取当前登录用户信息的方法
            return ok().setMessage("登录成功");
        }
        return ok().setMessage("登录失败");
    }

    // 查询登录状态，浏览器访问： http://localhost:8081/user/isLogin
    @ApiOperation("查询状态")
    @GetMapping("isLogin")
    public R<?> isLogin() {
        return ok("当前会话是否登录：" + StpUtil.isLogin());
    }
}


